package com.fansl.allround.auth.provider.ucenter.openid;

import cn.hutool.core.util.StrUtil;
import com.fansl.allround.auth.provider.social.qq.api.QQApi;
import com.fansl.allround.auth.provider.social.qq.bean.QQOpenId;
import com.fansl.allround.auth.provider.social.qq.bean.QQToken;
import com.fansl.allround.auth.provider.social.weibo.api.WeiboApi;
import com.fansl.allround.auth.provider.social.weibo.bean.WeiboToken;
import com.fansl.allround.common.core.constant.SecurityConstants;
import com.fansl.allround.common.core.constant.enums.OauthTypeEnum;
import lombok.Setter;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author fansl
 * @Description: ucenter用户登录验证filter
 * @date 2019/9/26 14:22
 */
public class OpenIdAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    @Setter
    private QQApi qqApi;
    @Setter
    private WeiboApi weiboApi;
    public static final String SPRING_SECURITY_FORM_PROVIDER_ID_KEY = "providerId";
    public static final String SPRING_SECURITY_FORM_CODE_KEY = "code";

    private String providerIdParameter = SPRING_SECURITY_FORM_PROVIDER_ID_KEY;
    private String codeParameter = SPRING_SECURITY_FORM_CODE_KEY;
    private boolean postOnly = false;

    public OpenIdAuthenticationFilter() {
        super(new AntPathRequestMatcher(SecurityConstants.UCENTER_SOCIAL_TOKEN_URL, HttpMethod.POST.name()));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (this.postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        } else {

            String providerId = this.obtainProviderId(request);
            String code = this.obtainCode(request);
            if (providerId == null) {
                providerId = "";
            }
            if (code == null) {
                throw new AuthenticationServiceException("code parameter must not be empty or null");
            }
            String openId = "";
            providerId = providerId.trim();
            code = code.trim();
            String accessToken = null;
            OauthTypeEnum oauthTypeEnum = OauthTypeEnum.getByCode(Integer.parseInt(providerId));
            switch (oauthTypeEnum) {
                case QQ: {
                    QQToken qqToken = qqApi.getAccessToken(code);
                    if (qqToken != null) {
                        accessToken = qqToken.getAccessToken();
                        QQOpenId qqOpenId = qqApi.getOpenId(accessToken);
                        openId = qqOpenId.getOpenId();
                    }
                    break;
                }
                case WEIBO:
                    WeiboToken weiboToken = weiboApi.getAccessToken(code);
                    if (weiboToken != null) {
                        accessToken = weiboToken.getAccessToken();
                        openId = weiboToken.getUid();
                    }
                    break;
                default:
                    throw new AuthenticationServiceException("oauth type not support");
            }
            if (StrUtil.isBlank(openId)) {
                throw new AuthenticationServiceException("openid get error");
            }
            OpenIdAuthenticationToken authRequest = new OpenIdAuthenticationToken(openId, providerId, accessToken);
            this.setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }

    protected void setDetails(HttpServletRequest request, OpenIdAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

    protected String obtainProviderId(HttpServletRequest request) {
        return request.getParameter(providerIdParameter);
    }

    public void setProviderIdParameter(String providerIdParameter) {
        Assert.hasText(providerIdParameter, "provider id parameter must not be empty or null");
        this.providerIdParameter = providerIdParameter;
    }

    public String getProviderIdParameter() {
        return this.providerIdParameter;
    }

    protected String obtainCode(HttpServletRequest request) {
        return request.getParameter(this.codeParameter);
    }

    public void setCodeParameter(String codeParameter) {
        Assert.hasText(codeParameter, "code parameter must not be empty or null");
        this.codeParameter = codeParameter;
    }

    public String getCodeParameter() {
        return this.codeParameter;
    }

    public void setPostOnly(boolean postOnly) {
        this.postOnly = postOnly;
    }
}
